﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using seiacpscs.sortalgorithms;
using seiacpscs.utilities;
using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;

namespace seiacpscs
{

    public class Sort
    {

        static String sortAlgorithm;
        static SortAlgorithm algorithm;
        static String inputFile;
        static String outputFile;
        static long memoryToTalInByes;
        static int[] items;
        static String outputText = "";

        static long fileParsingExecutionTime;
        static long fileWritingExecutionTime;

        static Stopwatch fileParsingStopWatch = new Stopwatch();
        static Stopwatch fileWritingStopWatch = new Stopwatch();

        static void Main(string[] args)
        {

            if (args.Length >= 3)
            {

                sortAlgorithm = args[0];
                inputFile = args[1];
                outputFile = args[2];

                switch (sortAlgorithm)
                {
                    case "bubblesort":
                        algorithm = SortAlgorithmFactory.BubbleSort;
                        break;
                    case "selectionsort":
                        algorithm = SortAlgorithmFactory.SelectionSort;
                        break;
                    default:
                        Console.WriteLine(args[0] + " is not a supported sorting algorithm.");
                        return;
                }


                //Measure the memory used
                //CancellationTokenSource cts = new CancellationTokenSource();
                //var memoryRecorderTask = new Task<long>(() => MeasureMemoryUsed(cts, 10), cts.Token);
                //memoryRecorderTask.Start();

                fileParsingStopWatch.Start();
                FileParser parser = new FileParser(inputFile);
                fileParsingStopWatch.Stop();

                fileParsingExecutionTime = (fileParsingStopWatch.ElapsedTicks * 1000L * 1000L * 1000L) / Stopwatch.Frequency; // Statistics Code

                items = parser.GetNumbers();
                algorithm.Sort(items);
                //Finish recording
                //cts.Cancel();
                //memoryRecorderTask.Wait();
                //memoryToTalInByes = memoryRecorderTask.Result;

                memoryToTalInByes = MeasureMemoryUsed();
                
                outputText = generateOutput();

                fileWritingStopWatch.Start();
                writeToFile(outputText, outputFile, false);
                fileWritingStopWatch.Stop();

                fileWritingExecutionTime = (fileWritingStopWatch.ElapsedTicks * 1000L * 1000L * 1000L) / Stopwatch.Frequency; // Statistics Code

                outputText = getStatistics();

                writeToFile(outputText, outputFile, true);

                Console.WriteLine("Generated output file : " + outputFile);

            }
            else
            {

                Console.WriteLine("Usage: Sort <sort_algorithm> <input_file> <output_file>");
            }
        }

        private static long MeasureMemoryUsed(CancellationTokenSource cts, int sleepTime)
        {
            int numberOfReadings = 0;
            long memoryUsedTotal = 0;
            Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
            while (!cts.IsCancellationRequested)
            {
                memoryUsedTotal += currentProcess.WorkingSet64;
                numberOfReadings++;
                Thread.Sleep(sleepTime);
            }
            return memoryUsedTotal / numberOfReadings;
        }

        private static long MeasureMemoryUsed()
        {
            long memoryUsed = 0;
            Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
            memoryUsed = currentProcess.WorkingSet64;
            return memoryUsed;
        }




        private static void writeToFile(String output, String filePath, bool isAppendModeOn)
        {

            StreamWriter writer = new StreamWriter(filePath,isAppendModeOn);
            writer.Write(output);
            writer.Close();
        }


        public static String getStatistics()
        {
            StringBuilder output = new StringBuilder();

            String line = "==================================================================================";
            String fileParsing = "File Parsing Time (Nano Seconds) : " + fileParsingExecutionTime;
            String algorithmName = "Algorithm Name : " + algorithm.AlorithmName;
            String noInnerLoops = "No. of Inner Loops : " + algorithm.NumberOfInnerLoops;
            String noOuterLoops = "No. of Outer Loops : " + algorithm.NumberOfOuterLoops;
            String noSwaps = "No. of Swaps : " + algorithm.NumberOfSwaps;
            String executionTime = "Sorting Execution Time (Nano Seconds) : " + algorithm.ExecutionTime;
            String fileWriting = "File Writing Time (Nano Seconds) : " + fileWritingExecutionTime;
            String totalMemUsed = "Memory Used (Bytes) : " + memoryToTalInByes;

            output.Append(line + "\r\n");
            output.Append(algorithmName + "\r\n");
            output.Append(fileParsing + "\r\n");
            output.Append(noInnerLoops + "\r\n");
            output.Append(noOuterLoops + "\r\n");
            output.Append(noSwaps + "\r\n");
            output.Append(executionTime + "\r\n");
            output.Append(fileWriting + "\r\n");
            output.Append(totalMemUsed + "\r\n");
            output.Append(line);

            return output.ToString();
        }


        public static String generateOutput()
        {
            StringBuilder output = new StringBuilder();

            for (int i = 0; i < items.Length; i++)
            {
                if (i < items.Length - 1)
                {
                    output.Append(items[i] + ",");
                }
                else
                {
                    output.Append(items[i] + "\r\n");
                }
            }

            return output.ToString();
        }
    }


}
